﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Odyssey.Controls.Internals;
using System.Windows.Threading;
using System.Collections.Generic;
using Odyssey.Effects;

namespace Odyssey.Controls.Primitives
{
    /// <summary>
    /// Panel used with OdcListBox to display the alphabetic quick jump list.
    /// </summary>
    public class QuickJumpWrapPanel : OdcVirtualizingPanel
    {
        public QuickJumpWrapPanel()
            : base()
        {
            for (int i = 0; i < 28; i++)
            {
                quickJumpItems.Add(new QuickJumpListBoxItem());
            }
            for (int i = 0; i < 7; i++)
            {
                QuickJumpRowPanel panel = new QuickJumpRowPanel { ItemWidth = 112d, ItemHeight = 112d };
                QuickJumpSwivelEffect.SetIsElement(panel, true);
                panel.CacheMode = new BitmapCache();
                Children.Add(panel);
                rowPanels.Add(panel);
            }
        }

        private List<QuickJumpListBoxItem> quickJumpItems = new List<QuickJumpListBoxItem>();
        private int maxItems = 40;

        private DispatcherTimer timer;

        public double ItemWidth
        {
            get { return (double)GetValue(ItemWidthProperty); }
            set { SetValue(ItemWidthProperty, value); }
        }

        public static readonly DependencyProperty ItemWidthProperty =
            DependencyProperty.Register("ItemWidth", typeof(double), typeof(QuickJumpWrapPanel), new PropertyMetadata(112.0));


        public static readonly DependencyProperty ColumnCountProperty =
            DependencyProperty.Register("ColumnCount", typeof(int), typeof(QuickJumpWrapPanel), new PropertyMetadata(4));


        protected override void OnUnloaded(object sender, RoutedEventArgs e)
        {
            base.OnUnloaded(sender, e);
            StopTimer();
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            double totalHeight = availableSize.Height;
            double totalWidth = availableSize.Width;

            IItemsControl itemsControl = ItemsControl;
            int count = itemsControl.ItemsSource != null ? itemsControl.ItemsSource.Count : 0;
            if (double.IsInfinity(totalHeight)) totalHeight = itemsControl.ItemHeight * count;
            if (double.IsInfinity(totalWidth)) totalWidth = 800d;

            if (IsInvalidated) Balance();

            totalHeight = totalHeight > 480d ? 800d : 480d;
            totalWidth = totalWidth > 480d ? 800d : 480d;
            return new Size(totalWidth, totalHeight);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            int n = ItemsControl.ItemsSource.Count;
            double w = ItemWidth;
            double h = ItemsControl.ItemHeight;

            double h0 = finalSize.Height > 480d ? 800d : 480d;
            double w0 = finalSize.Width > 480d ? 800d : 480d;

            int numColumns = (int)Math.Floor(w0 / w);
            int numRows = (int)Math.Ceiling((double)n / numColumns);

            double left = (w0 - numColumns * w) / 2.0;
            double top = (h0 - numRows * h) / 2.0;

            int columnIndex = 0;

            n = elements.Count;

            int rowCount = 0;

            Rect rect = new Rect(left, top, w, h);


            if (n > 0)
            {
                QuickJumpRowPanel rowPanel = NextRowPanel(rowCount, ref rect, finalSize.Width);
                for (int i = 0; i < n; i++)
                {
                    var child = elements[i];
                    if (rowPanel != child.Parent)
                    {
                        if (child.Parent != null)
                        {
                            (child.Parent as Panel).Children.Remove(child);
                        }
                        rowPanel.Children.Add(child);
                    }
                    if (++columnIndex < numColumns)
                    {
                        rect.X += w;
                    }
                    else
                    {
                        rowCount++;
                        columnIndex = 0;
                        rect.X = left;
                        rect.Y += h;
                        if (i < n - 1)
                        {
                            rowPanel = NextRowPanel(rowCount, ref rect, finalSize.Width);
                        }
                    }
                }
            }

            rect = new Rect(left, top, w, h);

            foreach (var child in Children)
            {
                if (rect.Y <= finalSize.Height)
                {
                    child.Arrange(rect);
                    rect.Y = rect.Bottom;
                }
                else child.Arrange(new Rect());
            }


            return finalSize;
        }


        private QuickJumpRowPanel NextRowPanel(int rowCount, ref Rect rect, double width)
        {
            if (rowPanels.Count <= rowCount)
            {
                throw new ArgumentNullException("NextRowPanel");
            }
            else
            {
                QuickJumpRowPanel panel = rowPanels[rowCount];
                return panel;
            }
        }

        private List<QuickJumpRowPanel> rowPanels = new List<QuickJumpRowPanel>();
        private List<FrameworkElement> elements = new List<FrameworkElement>();


        private void Balance()
        {
            var itemsControl = ItemsControl;
            IsInvalidated = false;
            var items = itemsControl.ItemsSource;
            if (items != null)
            {
                int n = items.Count;

                if (maxItems > n) maxItems = n;
                else if (maxItems < n)
                {
                    StartTimer();
                }
                OdcListBox lb = itemsControl as OdcListBox;
                for (int i = 0; i < maxItems; i++)
                {
                    QuickJumpListBoxItem item = quickJumpItems[i];
                    item.Content = item.DataContext = items[i];
                    item.ListBox = lb;
                    if (item.Parent == null) elements.Add(item);

                    //bool isNew;
                    //FrameworkElement item = itemsControl.GetItemContainer(i, out isNew);
                    //if (isNew)
                    //{
                    //    elements.Insert(i, item);
                    //    itemsControl.ItemContainerAttached(i, item);
                    //}
                }
            }
        }

        private void StartTimer()
        {
            if (timer == null || !timer.IsEnabled)
            {
                if (timer == null)
                {
                    timer = new DispatcherTimer
                    {
                        Interval = TimeSpan.FromMilliseconds(1.0)
                    };
                    timer.Tick += delegate
                    {
                        var itemsControl = ItemsControl;
                        int n = ItemsControl != null && itemsControl.ItemsSource != null ? itemsControl.ItemsSource.Count : 0;
                        int nextItems = maxItems + 4;
                        if (nextItems >= n)
                        {
                            nextItems = n;
                            StopTimer();
                        }
                        bool isNew;
                        for (int i = maxItems; i < nextItems; i++)
                        {
                            FrameworkElement item = itemsControl.GetItemContainer(i, out isNew);
                            this.Children.Add(item);
                        }
                        maxItems = nextItems;

                    };
                }
                else StopTimer();
                timer.Start();
            }
        }

        private void StopTimer()
        {
            if (timer != null && timer.IsEnabled) timer.Stop();
        }

        protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            Invalidate();
        }

        private void SetLoadState(UIElement item)
        {
            Control ctrl = item as Control;
            if (ctrl != null)
            {
                VisualStateManager.GoToState(ctrl, VisualStates.LoadedState, true);
            }
        }


        public override void ScrollIntoView(int itemIndex)
        {
        }


        protected internal override void Reset()
        {
            //      Children.Clear();
            base.Reset();
        }
    }
}
